#ifndef __CLX_UTIL_HPP__
#define __CLX_UTIL_HPP__

#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <sys/stat.h>
// #include <filesystem>
#include <experimental/filesystem>


namespace clx_cloud {
    namespace fs = std::experimental::filesystem;
    // namespace fs = std::filesystem;
    class FileUtil {
        private:
            std::string _filename;
        public:
            FileUtil(const std::string &filename) : _filename(filename){};
            int64_t FileSize() {
                struct stat st;
                if (stat(_filename.c_str(), &st) < 0) {
                    std::cout << "get file size failed! " << std::endl;
                    return -1;
                }
                return st.st_size;
            }

            time_t LastMTime() {
                struct stat st;
                if (stat(_filename.c_str(), &st) < 0) {
                    std::cout << "get file size failed! " << std::endl;
                    return -1;
                }
                return st.st_mtime;
            }

            time_t LastATime() {
                struct stat st;
                if (stat(_filename.c_str(), &st) < 0) {
                    std::cout << "get file size failed! " << std::endl;
                    return -1;
                }
                return st.st_atime;
            }

            std::string FileName() {
                size_t pos = _filename.find_last_of("/\\");
                if (pos == std::string::npos) {
                    return _filename;
                }
                return _filename.substr(pos + 1);
            }

            bool GetPosLen(std::string *body, size_t pos, size_t len) {
                size_t fsize = this->FileSize();
                if (pos + len > fsize) {
                    std::cout << "get file len is error" << std::endl;
                    return false;
                }
                std::ifstream ifs;
                ifs.open(_filename, std::ios::binary);
                if (ifs.is_open() == false) {
                    std::cout << "open file failed" << std::endl;
                    return false;
                }
                ifs.seekg(pos, std::ios::beg); // 从文件起始位置开始偏移到pos处
                body->resize(len);
                ifs.read(&(*body)[0], len);
                if (ifs.good() == false) {
                    std::cout << "get file Content failed" << std::endl;
                    return false;
                }
                ifs.close();
                return true;
            }

            bool GetContent(std::string *body) {
                size_t fsize = this->FileSize();
                return GetPosLen(body, 0, fsize);
            }

            bool SetContent(const std::string *body) {
                std::ofstream ofs;
                ofs.open(_filename, std::ios::binary);
                if (ofs.is_open() == false) {
                    std::cout << "write open file failed!" << std::endl;
                    return false;
                }
                ofs.write(&(*body)[0], body->size());
                if (ofs.good() == false) {
                    std::cout << "write file content failed!" << std::endl;
                    ofs.close();
                    return false;
                }
                ofs.close();
                return true;
            }


            bool Exists() { return fs::exists(_filename); }

            bool CreateDirectory() { 
                if (this->Exists()) return true;
                return fs::create_directories(_filename); 
            }

            bool Remove() {
                if (this->Exists() == false) return true;
                remove(_filename.c_str());
                return true;
            }

            bool ScanDirectory(std::vector<std::string> *array) {
                this->CreateDirectory();
                for (auto& entry : fs::directory_iterator(_filename)) {
                    if (!fs::is_directory(entry)) {
                        array->push_back(fs::path(entry).relative_path().string());
                    }
                }
                return true;
            }
    };

}

#endif
